<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>QeePHP 快速入门</title>
<link href="css/base.css" rel="stylesheet" type="text/css">
</head>
<body>

<div id="page">


<div class="guide-section">

  <div class="guide-header">
    <span class="nav">
      <a href="http://qee13.com/app/?action=docs">文档索引</a>
      &raquo;
      <a href="index.html">QeePHP 快速入门</a>
      &raquo;
      <a href="node-users.html">实现用户功能</a>
      &raquo;
      用户注册（功能实现）    </span>
  </div>

  <div class="guide-section-details formatted">
    
<h1>实现用户注册（功能实现）</h1>

<p>在前面的小结中，我们主要学习了怎么使用视图。现在我们来解决表单提交，以及模型的创建问题。</p>

<blockquote>
	<p>本章节和原来的教程有比较大的区别，为了更容易理解，把模型验证部分工作交给了controller，这个做法实际上并不利于模型的完整性</p>
</blockquote>

<h2>表单提交处理代码</h2>

<p>修改 controller/users.php 文件，加入以下代码：</p>

<pre class="php code"><span class="kw2">function</span> actionRegister<span
class="br0">&#40;</span><span class="br0">&#41;</span>
<span
class="br0">&#123;</span>
        <span class="kw1">if</span> <span
class="br0">&#40;</span>request_is_post<span class="br0">&#40;</span><span
class="br0">&#41;</span><span class="br0">&#41;</span><span
class="br0">&#123;</span>
                <span
class="co1">//从POST获取用户名和密码</span>
                <span
class="re0">$username</span> <span class="sy0">=</span> post<span
class="br0">&#40;</span><span class="st_h">'username'</span><span
class="br0">&#41;</span><span class="sy0">;</span>
                <span
class="re0">$password</span> <span class="sy0">=</span> post<span
class="br0">&#40;</span><span class="st_h">'password'</span><span
class="sy0">,</span><span class="st_h">''</span><span class="sy0">,</span><span
class="kw2">false</span><span class="br0">&#41;</span><span
class="sy0">;</span>
        <span class="br0">&#125;</span>
<span
class="br0">&#125;</span></pre>

<p>我们用到了QeePHP
自带的request_is_post函数和post函数，大家只需要阅读post函数的源代码就知道具体的原理，QeePHP还提供了
request、get、val等实用函数。</p>

<h2>验证数据有效性</h2>

<p>QeePHP 提供了模型级的验证方法，我们先用常规方法实现</p>

<pre class="php code"><span class="kw1">if</span> <span
class="br0">&#40;</span>request_is_post<span class="br0">&#40;</span><span
class="br0">&#41;</span><span class="br0">&#41;</span><span
class="br0">&#123;</span>
        <span class="kw1">do</span> <span
class="br0">&#123;</span>
                <span
class="co1">//从POST获取用户名和密码</span>
                <span
class="re0">$username</span> <span class="sy0">=</span> post<span
class="br0">&#40;</span><span class="st_h">'username'</span><span
class="br0">&#41;</span><span class="sy0">;</span>
                <span
class="re0">$password</span> <span class="sy0">=</span> post<span
class="br0">&#40;</span><span class="st_h">'password'</span><span
class="sy0">,</span><span class="st_h">''</span><span class="sy0">,</span><span
class="kw2">false</span><span class="br0">&#41;</span><span
class="sy0">;</span>
&nbsp;
                <span
class="co1">// 对输入数据进行验证</span>
                <span
class="re0">$errors</span> <span class="sy0">=</span> <span
class="kw3">array</span><span class="br0">&#40;</span><span
class="br0">&#41;</span><span class="sy0">;</span>
                <span
class="kw1">if</span> <span class="br0">&#40;</span><span
class="kw3">strlen</span><span class="br0">&#40;</span><span
class="re0">$username</span><span class="br0">&#41;</span> <span
class="sy0">&lt;</span> <span class="nu0">5</span><span
class="br0">&#41;</span>
                <span
class="br0">&#123;</span>
                        <span
class="re0">$errors</span><span class="br0">&#91;</span><span
class="st_h">'username'</span><span class="br0">&#93;</span><span
class="br0">&#91;</span><span class="br0">&#93;</span> <span
class="sy0">=</span> <span
class="st_h">'用户名不能少于 5 个字符'</span><span
class="sy0">;</span>
                <span
class="br0">&#125;</span>
                <span
class="co1">// 验证用户名有效性，更多验证方法请参考 QValidator</span>
                <span
class="kw1">if</span> <span class="br0">&#40;</span><span
class="sy0">!</span>QValidator<span class="sy0">::</span><span
class="me2">validate_is_alnum</span><span class="br0">&#40;</span><span
class="re0">$username</span><span class="br0">&#41;</span><span
class="br0">&#41;</span><span
class="br0">&#123;</span>
                        <span
class="re0">$errors</span><span class="br0">&#91;</span><span
class="st_h">'username'</span><span class="br0">&#93;</span><span
class="br0">&#91;</span><span class="br0">&#93;</span> <span
class="sy0">=</span> <span
class="st_h">'用户名只能由字母和数字组成'</span><span
class="sy0">;</span>
                <span
class="br0">&#125;</span>
                <span class="kw1">if</span> <span
class="br0">&#40;</span><span class="kw3">strlen</span><span
class="br0">&#40;</span><span class="re0">$password</span><span
class="br0">&#41;</span> <span class="sy0">&lt;</span> <span
class="nu0">6</span><span class="br0">&#41;</span>
                <span
class="br0">&#123;</span>
                        <span
class="re0">$errors</span><span class="br0">&#91;</span><span
class="st_h">'password'</span><span class="br0">&#93;</span><span
class="br0">&#91;</span><span class="br0">&#93;</span> <span
class="sy0">=</span> <span
class="st_h">'密码不能少于 6 个字符'</span><span
class="sy0">;</span>
                <span
class="br0">&#125;</span>
                <span
class="co1">//验证用户是否已经注册</span>
                <span
class="re0">$user</span><span class="sy0">=</span>User<span
class="sy0">::</span><span class="me2">find</span><span
class="br0">&#40;</span><span class="st_h">'username =?'</span><span
class="sy0">,</span><span class="re0">$username</span><span
class="br0">&#41;</span><span class="sy0">-&gt;</span><span
class="me1">getOne</span><span class="br0">&#40;</span><span
class="br0">&#41;</span><span class="sy0">;</span>
                <span
class="kw1">if</span> <span class="br0">&#40;</span><span
class="sy0">!</span><span class="re0">$user</span><span
class="sy0">-&gt;</span><span class="me1">isNewRecord</span><span
class="br0">&#40;</span><span class="br0">&#41;</span><span
class="br0">&#41;</span><span
class="br0">&#123;</span>
                        <span
class="re0">$errors</span><span class="br0">&#91;</span><span
class="st_h">'username'</span><span class="br0">&#93;</span><span
class="br0">&#91;</span><span class="br0">&#93;</span> <span
class="sy0">=</span> <span class="st_h">'用户名已经被注册'</span><span
class="sy0">;</span>
                <span
class="br0">&#125;</span>
                <span class="kw1">if</span> <span
class="br0">&#40;</span><span class="kw3">count</span><span
class="br0">&#40;</span><span class="re0">$errors</span><span
class="br0">&#41;</span><span class="br0">&#41;</span><span
class="br0">&#123;</span>
                        <span
class="re0">$this</span><span class="sy0">-&gt;</span>_view<span
class="br0">&#91;</span><span class="st_h">'errors'</span><span
class="br0">&#93;</span><span class="sy0">=</span><span
class="re0">$errors</span><span
class="sy0">;</span>
                        <span class="kw1">break</span><span
class="sy0">;</span>
                <span
class="br0">&#125;</span>
                <span
class="co1">//验证完毕，保存用户</span>
&nbsp;
        <span
class="br0">&#125;</span><span class="kw1">while</span> <span
class="br0">&#40;</span><span class="nu0">0</span><span
class="br0">&#41;</span><span class="sy0">;</span>
<span
class="br0">&#125;</span></pre>

<p>补充View部分错误显示</p>

<pre class="php
code">&lt;form name=&quot;form_user&quot; id=&quot;form_user&quot;
    action=&quot;<span
class="kw2">&lt;?php</span> <span class="kw3">echo</span> url<span
class="br0">&#40;</span><span class="st_h">'users/register'</span><span
class="br0">&#41;</span><span class="sy0">;</span> <span
class="kw2">?&gt;</span>&quot; method=&quot;post&quot;&gt;
&nbsp;
  &lt;fieldset&gt;
    &lt;p&gt;
      &lt;label for=&quot;username&quot;&gt;用户名&lt;/label&gt;
      &lt;input type=&quot;text&quot; name=&quot;username&quot; id=&quot;username&quot; /&gt;
      <span
class="kw2">&lt;?php</span> <span class="kw1">if</span> <span
class="br0">&#40;</span><span class="sy0">@</span><span
class="kw3">count</span><span class="br0">&#40;</span><span
class="re0">$errors</span><span class="br0">&#91;</span><span
class="st_h">'username'</span><span class="br0">&#93;</span><span
class="br0">&#41;</span><span class="br0">&#41;</span><span
class="br0">&#123;</span><span class="kw3">echo</span> <span
class="kw3">implode</span><span class="br0">&#40;</span><span
class="st_h">','</span><span class="sy0">,</span> <span
class="re0">$errors</span><span class="br0">&#91;</span><span
class="st_h">'username'</span><span class="br0">&#93;</span><span
class="br0">&#41;</span><span class="sy0">;</span><span
class="br0">&#125;</span><span
class="kw2">?&gt;</span>
    &lt;/p&gt;
&nbsp;
    &lt;p&gt;
      &lt;label for=&quot;password&quot;&gt;密码&lt;/label&gt;
      &lt;input type=&quot;password&quot; name=&quot;password&quot; id=&quot;password&quot; /&gt;
      <span
class="kw2">&lt;?php</span> <span class="kw1">if</span> <span
class="br0">&#40;</span><span class="sy0">@</span><span
class="kw3">count</span><span class="br0">&#40;</span><span
class="re0">$errors</span><span class="br0">&#91;</span><span
class="st_h">'password'</span><span class="br0">&#93;</span><span
class="br0">&#41;</span><span class="br0">&#41;</span><span
class="br0">&#123;</span><span class="kw3">echo</span> <span
class="kw3">implode</span><span class="br0">&#40;</span><span
class="st_h">','</span><span class="sy0">,</span> <span
class="re0">$errors</span><span class="br0">&#91;</span><span
class="st_h">'password'</span><span class="br0">&#93;</span><span
class="br0">&#41;</span><span class="sy0">;</span><span
class="br0">&#125;</span><span
class="kw2">?&gt;</span>
    &lt;/p&gt;
&nbsp;
    &lt;p&gt;
      &lt;input type=&quot;submit&quot; name=&quot;Submit&quot; value=&quot;提交&quot; /&gt;
    &lt;/p&gt;
&nbsp;
  &lt;/fieldset&gt;
&nbsp;
&lt;/form&gt;</pre>

<h2>完善模型定义</h2>

<p>时刻记住一点，QeePHP
是一个遵循“领域驱动开发”思想的框架。而领域驱动中，最重要的就是模型。而我们的大多数表单都是和模型有关的，所以在处理表单之前，首先要完善模型的定义。因为这些定义可以直接套入表单对象中，避免我们在不同的地方编写同样的逻辑，这就是
DRY 原则的最佳实践。</p>

<p>先前创建的 User
模型只是半成品，现在我们需要对其进行完善。一个模型由几个方面组成：</p>

<ul>
	<li>属性：定义模型有哪些属性、属性的类型以及属性的行为和验证规则等</li>

	<li>行为：添加实现业务逻辑需要的方法，让模型逐步逼近实际的需求</li>

	<li>数据：由属性和存储模型属性的数据表组成，但属性不一定要和数据表一一对应</li>

	<li>关系：模型需要互相配合来实现业务需求，因此关系也是模型的一部分</li>
</ul>

<h4>完善模型的属性</h4>

<p>打开模型的定义文件，在 __define()
方法中可以找到模型的详细定义。这些定义分为几个部分：</p>

<ul>
	<li>指定存储模型使用的数据表</li>

	<li>属性和关联的定义，例如只读属性、虚拟属性、关联等</li>

	<li>对属性的验证规则</li>

	<li>安全性方面的定义</li>

	<li>行为插件的定义</li>
</ul>

<p>在 QeePHP 的模型中，属性本身具有多种特性：</p>

<ul>
	<li>是否是只读属性</li>

	<li>是否是虚拟属性</li>

	<li>是否有 getter 或 setter 方法</li>

	<li>类型</li>

	<li>验证规则</li>
</ul>

<blockquote>
	<p>对于 todo
	这样的简单应用，我们用不到这么多高级特性，所以上述内容了解一下就行了。</p>
</blockquote>

<p>todo 应用中，user
模型只有两个主要属性：用户名和密码。根据需求，这两个属性有下列要求：</p>

<ul>
	<li>用户名应该是唯一的</li>

	<li>用户一旦成功创建，就不能更改用户名，因此用户名必须是只读属性</li>

	<li>用户名不能少于 5 个字符，不能多于 15
	个字符，并且只能使用字母和数字组成</li>

	<li>密码不能少于 6 个字符，不能多于 20 个字符</li>

	<li>密码应该加密存储</li>
</ul>

<p>现在我们一步步来实现这些要求。</p>

<p>用户名和密码的验证，之前在controller中已经实现，密码的加密存储我们让模型自己完成。在User模型（model\user.php）内加入以下代码</p>

<pre class="php code"><span class="kw3">static</span> <span
class="kw2">function</span> __define<span class="br0">&#40;</span><span
class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span
class="kw1">return</span> <span class="kw3">array</span>
    <span
class="br0">&#40;</span>
&nbsp;
        <span
class="co1">// 用什么数据表保存对象</span>
        <span
class="st_h">'table_name'</span> <span class="sy0">=&gt;</span> <span
class="st_h">'user'</span><span class="sy0">,</span>
&nbsp;
        <span
class="co1">// 指定数据表记录字段与对象属性之间的映射关系</span>
        <span
class="co1">// 没有在此处指定的属性，QeePHP 会自动设置将属性映射为对象的可读写属性</span>
        <span
class="st_h">'props'</span> <span class="sy0">=&gt;</span> <span
class="kw3">array</span>
        <span
class="br0">&#40;</span>
            <span class="st_h">'password'</span> <span
class="sy0">=&gt;</span> <span class="kw3">array</span><span
class="br0">&#40;</span><span class="st_h">'setter'</span> <span
class="sy0">=&gt;</span> <span class="st_h">'_password_setter'</span><span
class="br0">&#41;</span><span class="sy0">,</span>
        <span
class="br0">&#41;</span><span class="sy0">,</span>
    <span
class="br0">&#41;</span><span class="sy0">;</span>
<span
class="br0">&#125;</span>
<span
class="co4">/**
 * password Setter 修改模型password值自动加密
 * @param string $val
 */</span>
<span
class="kw2">function</span> _password_setter<span class="br0">&#40;</span><span
class="re0">$val</span><span class="br0">&#41;</span><span
class="br0">&#123;</span>
    <span class="re0">$this</span><span
class="sy0">-&gt;</span>_props<span class="br0">&#91;</span><span
class="st_h">'password'</span><span class="br0">&#93;</span><span
class="sy0">=</span><span class="kw2">self</span><span
class="sy0">::</span><span class="me2">passwordEncode</span><span
class="br0">&#40;</span><span class="re0">$val</span><span
class="br0">&#41;</span><span class="sy0">;</span>
    <span
class="re0">$this</span><span class="sy0">-&gt;</span><span
class="me1">willChanged</span><span class="br0">&#40;</span><span
class="st_h">'password'</span><span class="br0">&#41;</span><span
class="sy0">;</span>
<span class="br0">&#125;</span>
<span
class="co4">/**
 * 密码加密实现函数
 * @param string $val
 * @return string
 */</span>
<span
class="kw3">static</span> <span class="kw2">function</span> passwordEncode<span
class="br0">&#40;</span><span class="re0">$val</span><span
class="br0">&#41;</span><span class="br0">&#123;</span>
    <span
class="kw1">return</span> <span class="kw3">md5</span><span
class="br0">&#40;</span><span class="re0">$val</span><span
class="br0">&#41;</span><span class="sy0">;</span>
<span
class="br0">&#125;</span></pre>

<p>经过简单的设置，大部分要求都可以由 QeePHP
来处理了。</p>

<p>在users controller 增加一下代码：</p>

<pre class="php code"><span
class="co1">// 成功后输出新建用户对象的信息</span>
dump<span
class="br0">&#40;</span><span class="re0">$user</span><span
class="sy0">-&gt;</span><span class="me1">username</span><span
class="sy0">,</span> <span class="st_h">'UserName'</span><span
class="br0">&#41;</span><span class="sy0">;</span>
dump<span
class="br0">&#40;</span><span class="re0">$user</span><span
class="sy0">-&gt;</span><span class="me1">password</span><span
class="sy0">,</span> <span class="st_h">'Password'</span><span
class="br0">&#41;</span><span class="sy0">;</span>
dump<span
class="br0">&#40;</span><span class="re0">$user</span><span
class="sy0">-&gt;</span><span class="me1">id</span><span
class="br0">&#40;</span><span class="br0">&#41;</span><span
class="sy0">,</span> <span class="st_h">'UserID'</span><span
class="br0">&#41;</span><span class="sy0">;</span>
<span
class="kw3">exit</span><span class="sy0">;</span></pre>

<p>现在用浏览器访问 <a
href="http://localhost/app/index.php?controller=users&amp;action=register">http://localhost/app/index.php?controller=users&action=register</a>
，然后不输入任何内容就点击“提交”按钮，将可以看到如下界面：</p>

<div class="figure"><img src="images/users-register-code-01.png" alt="" />
	<p>对验证信息的反馈</p>
</div>

<p>现在输入用户名为：steven，密码为
123456，提交后会看到如下内容：</p>

<div class="figure"><img src="images/users-register-code-02.png" alt="" />
	<p>注册成功后的输出信息</p>
</div>

<p>通过 phpMyAdmin
可以看到刚刚输入的信息已经存入数据库了：</p>

<div class="figure"><img src="images/users-register-code-03.png" alt="" />
	<p>保存到数据库中的用户信息</p>
</div>

<p>为了方便后续开发，我们再修改一下 users 控制器的
actionRegister() 方法：</p>

<pre class="php code"><span
class="co1">// 成功后输出新建用户对象的信息</span>
dump<span
class="br0">&#40;</span><span class="re0">$user</span><span
class="sy0">-&gt;</span><span class="me1">username</span><span
class="sy0">,</span> <span class="st_h">'UserName'</span><span
class="br0">&#41;</span><span class="sy0">;</span>
dump<span
class="br0">&#40;</span><span class="re0">$user</span><span
class="sy0">-&gt;</span><span class="me1">password</span><span
class="sy0">,</span> <span class="st_h">'Password'</span><span
class="br0">&#41;</span><span class="sy0">;</span>
dump<span
class="br0">&#40;</span><span class="re0">$user</span><span
class="sy0">-&gt;</span><span class="me1">id</span><span
class="br0">&#40;</span><span class="br0">&#41;</span><span
class="sy0">,</span> <span class="st_h">'UserID'</span><span
class="br0">&#41;</span><span class="sy0">;</span>
<span
class="kw3">exit</span><span class="sy0">;</span></pre>

<p>改为：</p>

<pre class="php code"><span
class="co1">// 登录成功后，重定向浏览器</span>
<span
class="kw1">return</span> <span class="re0">$this</span><span
class="sy0">-&gt;</span>_redirect<span class="br0">&#40;</span>url<span
class="br0">&#40;</span><span class="st_h">'default/index'</span><span
class="br0">&#41;</span><span class="br0">&#41;</span><span
class="sy0">;</span></pre>

<p>现在读者朋友们可以发挥自己的想象力，尝试输入不同的内容来测试表单的验证规则、过滤器设置，以及对重复用户名的检查
:)</p>
$Id: users-register-code.texy 2013-08-14 02:24:25Z Tim13 $
  </div>

  <div class="guide-footer">

    <table border="0" width="100%">
      <tr>
        <td align="left" width="200">
                    &laquo;
          <a href="node-users-register-ui.html">用户注册（用户界面）</a>
          
        </td>

        <td align="center">
          本章：<a href="node-users.html">实现用户功能</a>
          <br />
          <a href="index.html">返回索引页</a>
        </td>

        <td align="right" width="200">
                    <a href="node-users-login.html">用户登录和注销</a> 
          &raquo;
                  </td>
      </tr>
    </table>

  </div>

</div>


</div>

</body>
</html>


